package com.heu.blood.statistic.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heu.blood.common.utils.PageUtils;
import com.heu.blood.common.utils.Query;
import com.heu.blood.dict.service.DictDepartmentService;
import com.heu.blood.dict.vo.DepartmentDictVo;
import com.heu.blood.match.dictenum.AboBloodTypeEnum;
import com.heu.blood.match.dictenum.BloodStateEnum;
import com.heu.blood.statistic.ManyEnum;
import com.heu.blood.statistic.dao.BloodUsageRankingDao;
import com.heu.blood.statistic.entity.BloodUsageRanking;
import com.heu.blood.statistic.entity.BloodUsageRankingVo;
import com.heu.blood.statistic.entity.BloodUsageUnitData;
import com.heu.blood.statistic.entity.EchartItem;
import com.heu.blood.statistic.service.BloodUsageRankingService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author bearH
 * @date 2023-09-08 10:24
 */
@Service("bloodUsageRankingService")
public class BloodUsageRankingServiceImpl extends ServiceImpl<BloodUsageRankingDao, BloodUsageRanking> implements BloodUsageRankingService {
    @Autowired
    private BloodUsageRankingDao bloodUsageRankingDao;

    @Autowired
    private DictDepartmentService dictDepartmentService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        Query<BloodUsageRanking> query = new Query<>();
        IPage<BloodUsageRanking> page = query.getPage(params);
        IPage<BloodUsageRanking> bloodUsageRankingIPage = bloodUsageRankingDao.queryPage(page, params);
        return new PageUtils(bloodUsageRankingIPage);
    }

    /*@Override
    public BloodUsageRankingVo getBloodUsageRanking() {
        BloodUsageRankingVo vo = new BloodUsageRankingVo();

        // 获取所有科室的code
        List<String> departmentCodes = bloodUsageRankingDao.getAllDepartmentCodes();
        vo.setXList(departmentCodes);  // 设置 X 轴为科室代码

        // 获取所有计量单位
        List<String> units = bloodUsageRankingDao.getAllUsedUnits();

        // 获取所有科室在所有单位下的用血统计
        List<BloodUsageUnitData> dataList = bloodUsageRankingDao.getUnitUsageByDepartment(BloodStateEnum.USED.code()); // 使用枚举

        // 初始化 unit -> 科室 -> 用血量 映射
        Map<String, Map<String, BigDecimal>> unitDeptMap = new HashMap<>();
        for (String unit : units) {
            unitDeptMap.put(unit, new HashMap<>());
            // 初始化所有科室默认值为0
            for (String dept : departmentCodes) {
                unitDeptMap.get(unit).put(dept, BigDecimal.ZERO);
            }
        }

        // 填充实际用血量数据
        for (BloodUsageUnitData data : dataList) {
            String unit = data.getUnit();
            String dept = data.getDepartment();
            BigDecimal count = data.getCount();
            if (unitDeptMap.containsKey(unit)) {
                unitDeptMap.get(unit).put(dept, count);
            }
        }

        // 填充 yList（科室的用血量），并按用血量降序排序
        Map<String, List<BigDecimal>> yList = new HashMap<>();
        for (String unit : units) {
            List<Map.Entry<String, BigDecimal>> sortedEntries = unitDeptMap.get(unit).entrySet()
                    .stream()
                    .sorted((entry1, entry2) -> entry2.getValue().compareTo(entry1.getValue())) // 按用血量降序排序
                    .collect(Collectors.toList());

            List<BigDecimal> sortedList = sortedEntries.stream()
                    .map(Map.Entry::getValue)
                    .collect(Collectors.toList());

            yList.put(unit, sortedList);
        }
        vo.setYList(yList);

        // 获取前10 + 其他（按单位分别处理）
        Map<String, List<EchartItem>> top10Map = new HashMap<>();
        for (String unit : units) {
            // 获取该单位下所有科室用血量（已按用血量降序排序）
            List<Map.Entry<String, BigDecimal>> sortedEntries = unitDeptMap.get(unit).entrySet()
                    .stream()
                    .sorted((entry1, entry2) -> entry2.getValue().compareTo(entry1.getValue()))
                    .collect(Collectors.toList());

            List<EchartItem> top10 = new ArrayList<>();
            BigDecimal otherValue = BigDecimal.ZERO;
            int validCount = 0; // 实际有效的前10名计数（用血量>0）

            for (Map.Entry<String, BigDecimal> entry : sortedEntries) {
                if (validCount < 10 && entry.getValue().compareTo(BigDecimal.ZERO) > 0) {
                    top10.add(new EchartItem(entry.getKey(), entry.getValue()));
                    validCount++;
                } else {
                    otherValue = otherValue.add(entry.getValue());
                }
            }

            // 如果"其他"有值（>0）或者前十名不足10个（有用血量为0的情况）
            if (otherValue.compareTo(BigDecimal.ZERO) > 0 || validCount < 10) {
                top10.add(new EchartItem(ManyEnum.OTHER.value(), otherValue));
            }

            top10Map.put(unit, top10);
        }
        vo.setTop10Map(top10Map);

        // 获取 ABO 血型占比（仅 ML 单位）
        if (units.contains(ManyEnum.ML.value())) {
            List<EchartItem> aboMlRatio = bloodUsageRankingDao.getAboRatioForMl();
            if (aboMlRatio != null) {
                // 确保按用血量降序排序
                aboMlRatio.sort((e1, e2) -> e2.getValue().compareTo(e1.getValue()));

                // 确保包含所有血型，即使为0
                Set<String> allAboTypes = Arrays.stream(AboBloodTypeEnum.values()) // 使用枚举类获取所有血型类型
                        .map(AboBloodTypeEnum::code) // 获取每个血型的代码
                        .collect(Collectors.toSet());
                Map<String, BigDecimal> aboMap = aboMlRatio.stream()
                        .collect(Collectors.toMap(EchartItem::getName, EchartItem::getValue));

                // 补充用血量为0的血型
                for (String aboType : allAboTypes) {
                    aboMap.putIfAbsent(aboType, BigDecimal.ZERO);
                }

                // 重新排序
                aboMlRatio = aboMap.entrySet().stream()
                        .map(entry -> new EchartItem(entry.getKey(), entry.getValue()))
                        .sorted((e1, e2) -> e2.getValue().compareTo(e1.getValue()))
                        .collect(Collectors.toList());
            }
            vo.setAboMlRatio(aboMlRatio);
        } else {
            vo.setAboMlRatio(Collections.emptyList());
        }

        return vo;
    }*/


    @Override
    public BloodUsageRankingVo getBloodUsageRanking() {
        BloodUsageRankingVo vo = new BloodUsageRankingVo();

        // 1. 获取完整的科室树
        List<DepartmentDictVo> tree = dictDepartmentService.getTreeRes();

        // 2. 获取所有计量单位
        List<String> units = bloodUsageRankingDao.getAllUsedUnits();

        // 3. 获取原始用血数据
        List<BloodUsageUnitData> rawDataList = bloodUsageRankingDao.getUnitUsageByDepartment(BloodStateEnum.USED.code());

        // 4. 构建 unit -> 一级科室 -> 用血量
        Map<String, Map<String, BigDecimal>> unitToDeptUsage = new HashMap<>();

        for (String unit : units) {
            Map<String, BigDecimal> deptUsage = new HashMap<>();
            unitToDeptUsage.put(unit, deptUsage);

            for (DepartmentDictVo root : tree) {
                List<String> allCodes = new ArrayList<>();
                collectCodes(root, allCodes);

                BigDecimal total = rawDataList.stream()
                        .filter(data -> unit.equals(data.getUnit()) && allCodes.contains(data.getDepartment()))
                        .map(BloodUsageUnitData::getCount)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);

                deptUsage.put(root.getCode(), total);
            }
        }

        // 5. 构建 Top5Map
        Map<String, List<EchartItem>> top5Map = new HashMap<>();
        for (String unit : units) {
            Map<String, BigDecimal> deptUsage = unitToDeptUsage.get(unit);

            // 过滤并排序
            List<Map.Entry<String, BigDecimal>> sorted = deptUsage.entrySet().stream()
                    .filter(entry -> entry.getValue().compareTo(BigDecimal.ZERO) > 0)
                    .sorted((a, b) -> b.getValue().compareTo(a.getValue()))
                    .collect(Collectors.toList());

            List<EchartItem> result = new ArrayList<>();
            BigDecimal otherValue = BigDecimal.ZERO;

            // 添加前5个有效科室
            int showCount = Math.min(sorted.size(), 5);
            for (int i = 0; i < showCount; i++) {
                result.add(new EchartItem(sorted.get(i).getKey(), sorted.get(i).getValue()));
            }

            // 处理"其他"项
            if (sorted.size() > 5) {
                // 有超过5个科室时，计算其他科室总和
                for (int i = 5; i < sorted.size(); i++) {
                    otherValue = otherValue.add(sorted.get(i).getValue());
                }
                result.add(new EchartItem(ManyEnum.OTHER.value(), otherValue));
            } else if (result.size() < 5) {
                // 不足5个科室时，添加一个"其他"（值为0）
                result.add(new EchartItem(ManyEnum.OTHER.value(), BigDecimal.ZERO));
            }

            top5Map.put(unit, result);
        }
        vo.setTop5Map(top5Map);

        // 6. 构建 xlist 和 ylist
        Map<String, List<String>> xlist = new HashMap<>();
        Map<String, List<BigDecimal>> ylist = new HashMap<>();

        for (String unit : units) {
            Map<String, BigDecimal> deptUsage = unitToDeptUsage.get(unit);

            // 过滤并排序
            List<Map.Entry<String, BigDecimal>> sorted = deptUsage.entrySet().stream()
                    .filter(entry -> entry.getValue().compareTo(BigDecimal.ZERO) > 0)
                    .sorted((a, b) -> b.getValue().compareTo(a.getValue()))
                    .collect(Collectors.toList());

            List<String> codes = new ArrayList<>();
            List<BigDecimal> values = new ArrayList<>();
            BigDecimal otherValue = BigDecimal.ZERO;

            // 添加前5个有效科室
            int showCount = Math.min(sorted.size(), 5);
            for (int i = 0; i < showCount; i++) {
                codes.add(sorted.get(i).getKey());
                values.add(sorted.get(i).getValue());
            }

            // 处理"其他"项
            if (sorted.size() > 5) {
                for (int i = 5; i < sorted.size(); i++) {
                    otherValue = otherValue.add(sorted.get(i).getValue());
                }
                codes.add(ManyEnum.OTHER.value());
                values.add(otherValue);
            } else if (codes.size() < 5) {
                // 不足5个科室时，添加一个"其他"（值为0）
                codes.add(ManyEnum.OTHER.value());
                values.add(BigDecimal.ZERO);
            }

            xlist.put(unit, codes);
            ylist.put(unit, values);
        }
        vo.setXlist(xlist);
        vo.setYlist(ylist);

        // 7. ABO 血型占比（只显示ML单位）
        if (units.contains(ManyEnum.ML.value())) {
            List<EchartItem> aboMlRatio = bloodUsageRankingDao.getAboRatioForMl();
            if (aboMlRatio != null) {
                aboMlRatio.sort((a, b) -> b.getValue().compareTo(a.getValue()));
                Set<String> allTypes = Arrays.stream(AboBloodTypeEnum.values())
                        .map(AboBloodTypeEnum::code).collect(Collectors.toSet());

                Map<String, BigDecimal> aboMap = aboMlRatio.stream()
                        .collect(Collectors.toMap(EchartItem::getName, EchartItem::getValue));
                for (String type : allTypes) {
                    aboMap.putIfAbsent(type, BigDecimal.ZERO);
                }

                aboMlRatio = aboMap.entrySet().stream()
                        .map(e -> new EchartItem(e.getKey(), e.getValue()))
                        .sorted((a, b) -> b.getValue().compareTo(a.getValue()))
                        .collect(Collectors.toList());
            }
            vo.setAboMlRatio(aboMlRatio);
        } else {
            vo.setAboMlRatio(Collections.emptyList());
        }

        return vo;
    }

    private void collectCodes(DepartmentDictVo node, List<String> codes) {
        codes.add(node.getCode());
        if (node.getChildren() != null) {
            for (DepartmentDictVo child : node.getChildren()) {
                collectCodes(child, codes);
            }
        }
    }





}









